package main

import (
	"autojs-tool-go/domain"
	"autojs-tool-go/utils"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/sirupsen/logrus"
	"io"
	"mime/multipart"
	"os"
	"strconv"
	"strings"
	//"github.com/gorilla/websocket"
	"log"
	"net/http"
	"time"
)

var upGrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	// 允许跨域
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func main() {
	// 设置在输出日志中添加文件名和方法信息
	logrus.SetReportCaller(true)
	//logrus.SetFormatter(&logrus.JSONFormatter{})

	mux := http.NewServeMux()
	mux.Handle("/", pages())
	mux.HandleFunc("/device/getOnlineDevice", getOnlineDevice)
	mux.HandleFunc("/device/getDeviceByAdmin", getDeviceByAdmin)
	mux.HandleFunc("/device/isNeedPassword", isNeedPassword)
	mux.HandleFunc("/device/validPassword", validPassword)
	mux.HandleFunc("/device/getOtherPropertyJson", getOtherPropertyJson)
	mux.HandleFunc("/device/sendMessageToClient", sendMessageToClient)

	mux.HandleFunc("/attachmentInfo/uploadFileSingle", uploadFileSingle) // 测试通过
	mux.HandleFunc("/attachmentInfo/uploadFileToAutoJs", uploadFileToAutoJs)
	mux.HandleFunc("/attachmentInfo/getAbsolutePrePath", getAbsolutePrePath)
	mux.HandleFunc("/attachmentInfo/queryAttachInfoListByPath", queryAttachInfoListByPath) // 测试通过
	mux.HandleFunc("/attachmentInfo/queryAllAttachInfoListByPath", queryAllAttachInfoListByPath)
	mux.HandleFunc("/attachmentInfo/uploadFile", uploadFile)
	mux.HandleFunc("/attachmentInfo/reNameFile", reNameFile) // 测试通过
	mux.HandleFunc("/attachmentInfo/copyFile", copyFile)
	mux.HandleFunc("/attachmentInfo/copyFileBatch", copyFileBatch)
	mux.HandleFunc("/attachmentInfo/moveFile", moveFile)
	mux.HandleFunc("/attachmentInfo/moveFileBatch", moveFileBatch)
	mux.HandleFunc("/attachmentInfo/createFolder", createFolder)       // 测试通过
	mux.HandleFunc("/attachmentInfo/deleteFile", deleteFile)           // 测试通过
	mux.HandleFunc("/attachmentInfo/deleteFileBatch", deleteFileBatch) // 测试通过

	mux.HandleFunc("/autoJsWs/", autoJsWs)

	server := &http.Server{
		Addr:    ":9998",
		Handler: mux,
	}

	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

func pages() http.Handler {
	logrus.Println(os.Getwd())
	return http.FileServer(http.Dir("./pages"))
}

// getOnlineDevice 获取在线设备
func getOnlineDevice(rw http.ResponseWriter, _ *http.Request) {
	var sl []domain.ClientInfo

	for _, v := range utils.Relation {
		sl = append(sl, *v.UserInfo)
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(sl))
	//dd, _ := json.Marshal(utils.JsonCamelCase{Value: new(domain.Rlt).Success().SetData(sl)})
	_, _ = rw.Write(dd)
}

// getDeviceByAdmin 管理员获取设备
func getDeviceByAdmin(rw http.ResponseWriter, r *http.Request) {
	var token = r.FormValue("token")
	if "www.zjh336.cn" != token {
		return
	}
	var deviceUUID = r.FormValue("deviceUUID")
	info := utils.Relation[deviceUUID].UserInfo
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(info))
	_, _ = rw.Write(dd)
}

// isNeedPassword 获取设备是否需要访问密码
func isNeedPassword(rw http.ResponseWriter, r *http.Request) {
	var deviceUUID = r.FormValue("deviceUUID")
	con := utils.Relation[deviceUUID]
	var rlt = false
	if con != nil {
		rlt = len(con.UserInfo.Password) > 0
	}
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(rlt))
	_, _ = rw.Write(dd)
}

// validPassword 验证访问密码
func validPassword(rw http.ResponseWriter, r *http.Request) {
	var deviceUUID = r.FormValue("deviceUUID")
	var password = r.FormValue("password")

	con := utils.Relation[deviceUUID]
	var rlt = false
	if con != nil {
		rlt = con.UserInfo.Password == password
	}
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(rlt))
	_, _ = rw.Write(dd)
}

// getOtherPropertyJson 获取其他属性
func getOtherPropertyJson(rw http.ResponseWriter, r *http.Request) {
	var deviceUUID = r.FormValue("deviceUUID")
	con := utils.Relation[deviceUUID]
	var rlt = ""
	if con != nil {
		rlt = con.UserInfo.OtherPropertyJson
	}
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(rlt))
	_, _ = rw.Write(dd)
}

// uploadFileToAutoJs 发送指令到客户端
func sendMessageToClient(rw http.ResponseWriter, r *http.Request) {
	var body = new(domain.AjMessage)
	body.MessageDateTime = domain.TimeStr(time.Now())
	//var b, _ = io.ReadAll(r.Body)
	_ = json.NewDecoder(r.Body).Decode(body)

	_ = utils.Relation[body.DeviceUuid].WsWrite(body)

	dd, _ := json.Marshal(new(domain.Rlt).Success())
	_, _ = rw.Write(dd)
}

// uploadFileSingle 上传附件
func uploadFileSingle(rw http.ResponseWriter, r *http.Request) {
	var pathName = r.FormValue("pathName")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	if r.Method == "POST" {
		file, fileHeader, _ := r.FormFile("file")
		defer func(file multipart.File) {
			_ = file.Close()
		}(file)

		// 写入文件
		var path = "./pages/uploadPath/autoJsTools/" + pathName + "/" + fileHeader.Filename
		utils.SaveFile(file, path)
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData("uploadPath/autoJsTools/" + pathName))
	_, _ = rw.Write(dd)
}

// uploadFileToAutoJs 上传附件(AutoJs专用)
func uploadFileToAutoJs(rw http.ResponseWriter, r *http.Request) {
	var imageName = r.FormValue("imageName")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	if r.Method == "POST" {
		file, _, _ := r.FormFile("file")
		defer func(file multipart.File) {
			_ = file.Close()
		}(file)

		// 写入文件
		var path = "./pages/uploadPath/autoJsTools/" + imageName
		utils.SaveFile(file, path)
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData("uploadPath/autoJsTools/" + imageName))
	_, _ = rw.Write(dd)
}

// getAbsolutePrePath 获取绝对路径前缀
func getAbsolutePrePath(rw http.ResponseWriter, r *http.Request) {
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData("./pages/uploadPath/autoJsTools/"))
	_, _ = rw.Write(dd)
}

// queryAttachInfoListByPath 根据相对路径获取子文件以及子目录(不递归)
func queryAttachInfoListByPath(rw http.ResponseWriter, r *http.Request) {
	var relativeFilePath = r.FormValue("relativeFilePath")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	filePath := "./pages/uploadPath/autoJsTools/" + relativeFilePath
	root, files := utils.FileList(filePath, false)
	attachInfos := domain.ConvertAttr(root, files)

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(attachInfos))
	_, _ = rw.Write(dd)
}

// queryAllAttachInfoListByPath 根据相对路径获取子文件以及子目录(递归)
func queryAllAttachInfoListByPath(rw http.ResponseWriter, r *http.Request) {
	var relativeFilePath = r.FormValue("relativeFilePath")
	onlyQueryFolder, _ := strconv.ParseBool(r.FormValue("onlyQueryFolder"))
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	filePath := "./pages/uploadPath/autoJsTools/" + relativeFilePath

	var loop func(dir string, onlyQueryFolder bool) []*domain.AttachInfo
	loop = func(dir string, onlyQueryFolder bool) []*domain.AttachInfo {
		root, files := utils.FileList(dir, onlyQueryFolder)
		attachInfos := domain.ConvertAttr(root, files)

		for _, attachInfo := range attachInfos {
			if attachInfo.IsDirectory {
				children := loop(attachInfo.PathName, onlyQueryFolder)
				attachInfo.Children = children
			}
		}
		return attachInfos
	}

	attachInfos := loop(filePath, onlyQueryFolder)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(attachInfos))
	_, _ = rw.Write(dd)
}

// uploadFile 上传文件
func uploadFile(rw http.ResponseWriter, r *http.Request) {
	var fileName = r.FormValue("fileName")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	info := domain.AttachInfo{}
	if r.Method == "POST" {
		file, _, _ := r.FormFile("file")
		defer func(file multipart.File) {
			_ = file.Close()
		}(file)

		// 写入文件
		var path = "./pages/uploadPath/autoJsTools/" + fileName
		utils.SaveFile(file, path)
		info = domain.ConvertAttrByFile("./pages/uploadPath/autoJsTools/", path)
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(info))
	_, _ = rw.Write(dd)
}

// reNameFile 复制文件(单个文件，递归复制)
func reNameFile(rw http.ResponseWriter, r *http.Request) {
	var oldFilePathName = r.FormValue("oldFilePathName")
	var newFilePathName = r.FormValue("newFilePathName")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	ok := utils.ReNameFile("./pages/uploadPath/autoJsTools/", oldFilePathName, newFilePathName)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(ok))
	_, _ = rw.Write(dd)
}

// copyFile 复制文件(单个文件，递归复制)
func copyFile(rw http.ResponseWriter, r *http.Request) {
	var sourcePath = r.FormValue("sourcePath")
	var targetFolderPath = r.FormValue("targetFolderPath")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	ok := utils.CopyFile("./pages/uploadPath/autoJsTools/", sourcePath, targetFolderPath)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(ok))
	_, _ = rw.Write(dd)
}

// copyFileBatch 批量复制文件(多个文件，递归复制)
func copyFileBatch(rw http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
		_ = r.Body.Close()
	}()

	if r.Method == "POST" {
		BodyData, _ := io.ReadAll(r.Body)

		var params map[string]interface{}
		_ = json.Unmarshal(BodyData, &params)

		targetFolderPath := params["targetFolderPath"].(string)
		sourcePathList := params["sourcePathList"].([]string)

		for _, s := range sourcePathList {
			_ = utils.CopyFile("./pages/uploadPath/autoJsTools/", s, targetFolderPath)
		}
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(true))
	_, _ = rw.Write(dd)
}

// moveFile 移动文件(单个文件，递归移动)
func moveFile(rw http.ResponseWriter, r *http.Request) {
	var sourcePath = r.FormValue("sourcePath")
	var targetFolderPath = r.FormValue("targetFolderPath")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	ok := utils.MoveFile("./pages/uploadPath/autoJsTools/", sourcePath, targetFolderPath)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(ok))
	_, _ = rw.Write(dd)
}

// moveFileBatch 批量移动文件(多个文件，递归移动)
func moveFileBatch(rw http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
		_ = r.Body.Close()
	}()

	if r.Method == "POST" {
		BodyData, _ := io.ReadAll(r.Body)

		var params map[string]interface{}
		_ = json.Unmarshal(BodyData, &params)

		targetFolderPath := params["targetFolderPath"].(string)
		sourcePathList := params["sourcePathList"].([]string)

		for _, s := range sourcePathList {
			_ = utils.MoveFile("./pages/uploadPath/autoJsTools/", s, targetFolderPath)
		}
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(true))
	_, _ = rw.Write(dd)
}

// createFolder 创建文件夹
func createFolder(rw http.ResponseWriter, r *http.Request) {
	var folderName = r.FormValue("folderName")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	ok := utils.CreateFolder("./pages/uploadPath/autoJsTools/" + folderName)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(ok))
	_, _ = rw.Write(dd)
}

// deleteFile 删除文件(递归删除)
func deleteFile(rw http.ResponseWriter, r *http.Request) {
	var filePath = r.FormValue("filePath")
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
	}()

	ok := utils.DeleteFile("./pages/uploadPath/autoJsTools/", filePath)
	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(ok))
	_, _ = rw.Write(dd)
}

// deleteFileBatch 批量删除文件(递归删除)
func deleteFileBatch(rw http.ResponseWriter, r *http.Request) {
	defer func() {
		if err := recover(); err != nil {
			logrus.Println(err)
			dd, _ := json.Marshal(new(domain.Rlt).Fail(domain.ServiceError, fmt.Sprintf("%s", err)))
			_, _ = rw.Write(dd)
		}
		_ = r.Body.Close()
	}()

	if r.Method == "POST" {
		BodyData, _ := io.ReadAll(r.Body)

		var filePathList []string
		_ = json.Unmarshal(BodyData, &filePathList)

		for _, s := range filePathList {
			_ = utils.DeleteFile("./pages/uploadPath/autoJsTools/", s)
		}
	}

	dd, _ := json.Marshal(new(domain.Rlt).Success().SetData(true))
	_, _ = rw.Write(dd)
}

func autoJsWs(w http.ResponseWriter, r *http.Request) {
	//升级成功后将获取到WebSocket.Conn 利用这个Conn可进行消息收发
	wsSocket, err := upGrader.Upgrade(w, r, nil)
	if err != nil {
		fmt.Println("upgrade error")
		return
	}

	split := strings.Split(r.RequestURI, "/")
	deviceUuid := split[2]
	deviceHeight, _ := strconv.Atoi(split[3])
	deviceWidth, _ := strconv.Atoi(split[4])

	wsConn := utils.WsConnection{
		Id:        deviceUuid,
		WsSocket:  wsSocket,
		InChan:    make(chan *domain.AjMessage, 64),
		OutChan:   make(chan *domain.AjMessage, 64),
		CloseChan: make(chan byte),
		IsClosed:  false,
		UserInfo: &domain.ClientInfo{
			DeviceUuid:    deviceUuid,
			ScreenHeight:  deviceHeight,
			ScreenWidth:   deviceWidth,
			ConnectTime:   domain.TimeStr(time.Now()),
			LastHeartTime: domain.TimeStr(time.Now()),
		},
	}
	go handle(&wsConn)
	// 添加连接对应关系
	utils.RegisterConnect(&wsConn)

	var rltMsg = "连接成功！" + deviceUuid
	logrus.Println(rltMsg)
	_ = wsSocket.WriteMessage(websocket.TextMessage, []byte(rltMsg))
}

func handle(conn *utils.WsConnection) {
	for {
		read, err := conn.WsRead()
		if err != nil {
			break
		}

		conn.UserInfo.LastHeartTime = domain.TimeStr(time.Now())

		if len(read.Message) > 0 && read.Message == "0" {
			param := domain.AjMessage{Message: "1"}
			_ = conn.WsWrite(&param)
		}

		if "sendDeviceInfo" == read.Action && len(read.Message) > 0 {
			dec, _ := base64.StdEncoding.DecodeString(read.Message)
			var m = map[string]interface{}{}
			_ = json.Unmarshal(dec, &m)
			conn.UserInfo.ScreenWidth = int(m["deviceWidth"].(float64))
			conn.UserInfo.ScreenHeight = int(m["deviceHeight"].(float64))
			conn.UserInfo.Password = m["password"].(string)

			otherPropertyJson := m["otherPropertyJson"].(string)
			decodeString, _ := base64.StdEncoding.DecodeString(otherPropertyJson)
			conn.UserInfo.OtherPropertyJson = string(decodeString)
		}
	}
}
